package chp;

import java.util.StringTokenizer;

/*
 * Basically this program is made of the following parts:
 * 1) One part that handles the input files and performs some checks to ensure that it is ok
 * 2) One part that tries to find a solution for the problem
 * 3) One part that checks if a given solution is valid. The solution could be given either 
 * as output from an algorithm (i.e. part 2) ) or as a separate file
 * 
 * This program is so structured:
 * - class "InputAnalyzer" that handles the WIC files, checks them and returns the data contained in them in some
 * appropriate way
 * - class "SolutionProducer" handles part 2)
 * - class "SolutionChecker", handles part 3)
 *
 * CHP class additionally provides means to write the solution into a file.
 */


public class CHP {

	// takes in input the WIC file and, optionally the WSO file
	public static void main(String[] args) 
	{
		CHP chp = new CHP();
		
		SessionOptions so = chp.processArguments(args);
		
		if(so==null){
			printHelp();
			System.exit(1);
		}
			
		String ifile = so.getProblem();
		String ofile = so.getSolution();
		int[] options = so.getOptions();
		
		try {
			WICInput problemData = IOHandler.decodeInputFile(ifile);
			WICOutput solutionData=null,solutionData1=null,solutionData2=null,solutionData3=null;
			//SolutionProducer sp = new SolutionProducer(problemData);//initialize -- I suggest to make it static though
			
			//let's process the stuff now
			if(options[0] == 0){
				solutionData = IOHandler.decodeOutputFile(ofile);
				if(SolutionChecker.checkSolution(problemData,solutionData)==0)
					System.out.println("\n[OK] The solution is valid\n");
				else if(SolutionChecker.checkSolution(problemData,solutionData)==1)
					System.out.println("\n[NOT OK] The K of the solution ("+solutionData.getK()+") is greater than the one ("+problemData.getK()+") required by the problem\n");
				else
					System.out.println("\n[NOT OK] The solution doesn't match the problem\n");
				System.out.println(generateReport(ifile,new String[]{"SOLUTION"},problemData,new WICOutput[]{solutionData}));
			} 
			else if(options[0] == 1){
				if(options[2] == 1){
					solutionData = SolutionGenerator.equalNumbersFirst(problemData);
					System.out.println(generateReport(ifile,new String[]{"SolutionGenerator.equalNumbersFirst()"},problemData,new WICOutput[]{solutionData}));
					IOHandler.generateOutputFile(ofile, solutionData);
				}
				else if(options[2] == 2){
					solutionData = SolutionGenerator.generateSolutionMin(problemData);
					System.out.println(generateReport(ifile,new String[]{"SolutionGenerator.generateSolutionMin()"},problemData,new WICOutput[]{solutionData}));
					IOHandler.generateOutputFile(ofile, solutionData);
				}
				else if(options[2] == 3){
					solutionData = SolutionGenerator.generateSolutionMax(problemData);
					System.out.println(generateReport(ifile,new String[]{"SolutionGenerator.generateSolutionMax()"},problemData,new WICOutput[]{solutionData}));
					IOHandler.generateOutputFile(ofile, solutionData);
				}
				else{//we want to use all the algorithms...
					solutionData1 = SolutionGenerator.equalNumbersFirst(problemData);
					solutionData2 = SolutionGenerator.generateSolutionMin(problemData);
					solutionData3 = SolutionGenerator.generateSolutionMax(problemData);
					System.out.println(generateReport(ifile,new String[]{"SolutionGenerator.equalNumbersFirst()",
							"SolutionGenerator.generateSolutionMin()",
							"SolutionGenerator.generateSolutionMax()"},
							problemData,new WICOutput[]{solutionData1,solutionData2,solutionData3}));
					String[] ofiles = generateOutputFileName(ifile, new String[]{"equalNumbersFirst","generateSolutionMin","generateSolutionMax"});
					IOHandler.generateOutputFile(ofiles[0], solutionData1);
					IOHandler.generateOutputFile(ofiles[1], solutionData2);
					IOHandler.generateOutputFile(ofiles[2], solutionData3);
				}
				
			}
			
				if(options[1] == 1){//don't provide files
					if(options[0] == 0){//we did --check
						System.out.println(IOHandler.solutionPicture("Solution",problemData, solutionData));
						System.out.println();
					}
					else{ // we did --gen
						if(options[2] == 0){
							System.out.println(IOHandler.solutionPicture("SolutionGenerator.equalNumbersFirst()",problemData, solutionData1));
							System.out.println("\n\n");
							System.out.println(IOHandler.solutionPicture("SolutionGenerator.generateSolutionMin()",problemData, solutionData2));
							System.out.println("\n\n");
							System.out.println(IOHandler.solutionPicture("SolutionGenerator.generateSolutionMax()",problemData, solutionData3));
							System.out.println();
						}
						else{//we chose an algorithm
							String alg = null;
							switch(options[2]){
							case 1: 
								alg = "SolutionGenerator.equalNumbersFirst()";
								break;
							case 2: 
								alg = "SolutionGenerator.generateSolutionMin()";
								break;
							case 3: 
								alg = "SolutionGenerator.generateSolutionMax()";
								break;
							}
							System.out.println(IOHandler.solutionPicture(alg,problemData, solutionData));
							System.out.println();
						}
					}
				}
				else if(options[1] == 0){//we provide files
					solutionData = IOHandler.decodeOutputFile(ofile);
					System.out.println(IOHandler.solutionPicture("Solution",problemData, solutionData));
					System.out.println();
				}
		
		} catch (InputFileException e) {
			System.err.println(e.getErrorMessage());
		} catch (OutputFileException e) {
			System.err.println(e.getErrorMessage());
		}
	}

	/*
	 * This class determines what must be done during this session
	 */
	private class SessionOptions{
		
		/*
		 * 0 = false
		 * 1..N = yes / option number
		 * 
		 * int[0] = check/gen (0/1)
		 * int[1] = show representation (-1=no, 0=files provided, 1 = files provided by gen or check)
		 * int[2] = algorithm chosen 1, 2 or 3
		 */
		private final int[] options;
		private final String problem;
		private final String solution;
		
		SessionOptions(int[] options, String problem, String solution){
			this.options = options;
			this.problem = problem;
			this.solution = solution;
		}
		
		SessionOptions(int[] options, String problem){
			this.options = options;
			this.problem = problem;
			this.solution = null;
		}

		int[] getOptions() {
			return options;
		}

		String getProblem() {
			return problem;
		}

		String getSolution() {
			return solution;
		}
	}
	
	
	private static String generateReport(String iFileName, String[] algNames, WICInput idata, WICOutput[] odata){
		String idataReport = 
			"\nINPUT PROBLEM: "+iFileName+"\n######################################################\n" +
			"n = "+idata.getN()+"\n"+
			"K = "+idata.getK()+"\n\n";
		
		String odataReports = "";
		String temp = "";
		if(odata.length==1)
			odataReports = algNames[0]+"\n######################################################\n" + "K = "+odata[0].getK()+"\n\n";
		else{
			for(int i=0; i<odata.length; i++){
				temp =
					algNames[i]+(i+1)+"\n#################\n" +
					"K = "+odata[i].getK()+"\n\n";
				odataReports += temp;
			}
		}
		return idataReport + odataReports+"~~~~~~~~~~~~~~~~~~~~~~~";
	}
	
	
	/*
	 * if return null, print help!
	 */
	private SessionOptions processArguments(String[] args){
		if(args.length < 2)
			return null;
		
		String ifile = null,ofile = null;
		int[] options = new int[]{-1,-1,-1}; //defaults
		
		try{
		
			for(int i=0; i<args.length; i++){
				
				if( args[i].equals("-c") || args[i].equals("--check-solution")){
					ifile = args[++i];
					ofile = args[++i];
					options[0] = 0; //set "check" flag
					continue;
				}
				
				if( args[i].equals("-g") || args[i].equals("--generate-solution")){
					ifile = args[++i];
					if( (args.length-(i+1) > 0) && (args[i+1].charAt(0) != '-') )
						ofile = args[++i];
					else
						ofile = generateOutputFileName(ifile,null)[0];
					options[0] = 1;
					continue;
				}
					
				if( args[i].equals("-s") || args[i].equals("--show-representation")){
					if( (args.length-(i+1) > 0) && (args[i+1].charAt(0) != '-') ){
						ifile = args[++i];
						ofile = args[++i];
						options[1] = 0;
					}
					else 
						options[1] = 1;
					continue;
				}
				
				if( args[i].equals("-a") || args[i].equals("--algorithm")){
					if(args[i+1].equals("0"))
						options[2] = 0;
					else if(args[i+1].equals("1"))
						options[2] = 1;
					else if(args[i+1].equals("2"))
						options[2] = 2;
					else if(args[i+1].equals("3"))
						options[2] = 3;
					i++;
					continue;
				}
				
				return null; //if we fall here we don't know the argument or it is "--help". Any case.. print help
			} 
		} catch (ArrayIndexOutOfBoundsException e){
			return null;
		}
		
		/*
		 * before returning the SessioOptions, let's check if the options selected are consistent.
		 * We must check the following:
		 * - if int[1]==1 then it must be int[0]!=-1
		 * - if int[1]==2 then it must be int[0]==0
		 */
		if( (options[1] == 1 && options[0] == -1) || (options[1]==0 && options[0] != -1))
			return null;
		if(options[2] == -1)//if we didn't select an algorithm, default to 1
			options[2] = 1;
		
		return this.new SessionOptions(options,ifile,ofile);
	}
			
		
			
	private static String[] generateOutputFileName(String ifName, String[] append){
		StringTokenizer st = new StringTokenizer(ifName,".");
		int i = st.countTokens();
		String ofName = "";
		
		if(append==null){
			
			while(i > 1){
				ofName += st.nextToken()+".";
				i--;
			}
			
			ofName += "WSO";
			
			return new String[]{ofName};
		}
		else{
			String[] names = new String[append.length];

			while(i > 1){//get the first part of the name
				ofName += st.nextToken()+".";
				i--;
			}
			for(int z=0; z< append.length; z++)
				names[z]=ofName+append[z]+".WSO";
			
			return names;
		}
	}
	
	
	//prints the help to the user
	private static void printHelp(){
		System.out.print("Usage: \n\t java CHP [options] file1.WIC [file2.WSO]" +
				"\n\t java -jar CHP.jar [options] file1.WIC [file2.WSO]\n\n" +
				"Options:\n" +
				
				"-c, --check-solution file1.WIC file2.WSO\n\tChecks if \"file2.WSO\" represents a valid solution to the problem encoded in \"file1.WIC\"." +
				"\n\tExample: java CHP --check file1.WIC file2.WSO\n\n" +
				
				"-g, --generate-solution file1.WIC [file2.WSO]\n\tGenerate a solution for \"file1.WIC\". If \"file2.WSO\" is given the solution is stored there" +
				"\n\totherwise it is stored in the current directory under name\"file1.WSO\"." +
				"\n\tExample: java CHP --generate-solution file1.WIC file2.WSO\n\n" +
				
				"-s, --show-representation [file1.WIC] [file2.WSO]\n\tPrints a picture representing a problem and its solution." +
				"\n\tExample: java CHP --show-representation file1.WIC file2.WSO" +
				"\n\t         java CHP --show-representation --generate-solution file1.WIC file2.WSO\n\n" +
				
				"-a, --algorithm {0,1,2,3}\n\tChoose which algorithm to use to generate the solution. The default is to use the first one" +
				"\n\t   1 = SolutionChecker.equalNumbersFirst()" +
				"\n\t   2 = SolutionChecker.generateSolutionMin()" +
				"\n\t   3 = SolutionChecker.generateSolutionMax()" +
				"\n\t   0 = Select all the algorithms\n\n" +				
				"-h, --help\n\tPrint this help page\n\n");
	}

}
